<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>购物车</title>
  <style>
    .active {
      background-color: #ddd;
    }

    .message-box {
      padding: 10px 20px;
    }

    .success {
      background: #4fc08d;
      border: 1px solid #42b983;
    }

    .warning {
      background: #f66;
      border: 1px solid #d63200;
    }

    .message-box-close {
      float: right;
    }

    .icon {
      width: 1em;
      height: 1em;
      vertical-align: -0.15em;
      fill: currentColor;
      overflow: hidden;
    }
  </style>
  <script src="https://at.alicdn.com/t/font_1281272_fepjp89tyz9.js"></script>
</head>

<body>
  <!-- 宿主文件 -->
  <div id="app">
    <!-- 弹窗组件 -->
    <!-- <message :show.sync="show" class="success"> -->
    <message ref="msgSuccess" class="success">
      <!-- 命名为title插槽内容 -->
      <template v-slot:title="slotProps">
        <strong>{{slotProps.title}}</strong>
      </template>
      <!-- 默认插槽内容 -->
      <template v-slot:default>
        新增课程成功!
      </template>
    </message>

    <!-- <message :show.sync="showWarn" class="warning"> -->
    <message ref="msgWarning" class="warning">
      <!-- 命名为title插槽内容 -->
      <template v-slot:title>
        <strong>警告</strong>
      </template>
      <!-- 默认插槽内容 -->
      <template v-slot:default>
        请输入课程名称!
      </template>
    </message>


    <!-- 使用render方法实现heading组件 -->
    <heading level="1" :title="title" icon="gouwuche">
      {{title}}
    </heading>
    <h2 :title="title">
      <svg class="icon">
        <use xlink:href="#icon-gouwuche"></use>
      </svg>
      <!-- 插值文本 -->
      {{title}}
    </h2>

    <!-- toolbar -->
    <div class="toolbar" v-permission="'admin'">
      <button @click="$bus.$emit('message-close')">清空提示框</button>
    </div>

    <!-- 新增课程 -->
    <course-add v-model="course" @add-course="addCourse"></course-add>
    <!-- <course-add :value="course" @input="course=$event" @add-course="addCourse"></course-add> -->

    <!-- 批量更新价格 -->
    <p>
      <input type="text" v-model.number="price">
      <button @click="batchUpdate">批量更新价格</button>
    </p>

    <!-- 列表组件 -->
    <course-list :courses="courses"></course-list>

    <!-- 商品总数 -->
    <p>
      <!-- 表达式 -->
      <!-- 课程总数：{{courses.length + '门'}} -->
      <!-- 计算属性 -->
      <!-- 课程总数：{{total}} -->
      <!-- 监听器 -->
      课程总数：{{totalCount}}
    </p>
  </div>

  <script src="vue.js"></script>
  <script>
    // 模拟用户角色
    const role = 'user'

    // 总线
    Vue.prototype.$bus = new Vue();

    // heading组件
    // <heading :level="1" :title="title" icon="cart">{{title}}</heading>
    // <h2 title=""></h2>
    Vue.component('heading', {
      functional: true, // 函数式组件
      props: {
        level: {
          type: String,
          required: true
        },
        title: {
          type: String,
          default: ''
        },
        icon: {
          type: String
        }
      },
      render(h, context) {
        // 子节点数组
        let children = []

        console.log(context);
        
        // 属性获取
        const {icon, title, level} = context.props;

        // icon属性处理逻辑
        if (icon) {
          // <svg class="icon"><use xlink:href="#icon-cart"/></svg>
          children.push(h(
            'svg',
            { class: 'icon' },
            [h('use', { attrs: { 'xlink:href': '#icon-' + icon } })]
          ))

        }

        // 拼接子节点
        children = children.concat(context.children)

        const vnode = h(
          'h' + level, // 参数1：tagname
          { attrs: { title } }, // 参数2：{。。。}
          children // 参数3：子节点VNode数组
        )
        console.log(vnode);
        // 返回createElement返回的VNode
        return vnode
      }
    })

    // 弹窗组件
    Vue.component('message', {
      // props: ['show'],
      data() {
        return {
          show: false
        }
      },
      template: `
        <div class="message-box" v-if="show">
          <!--具名插槽-->
          <slot name="title" title="来自message的标题">默认标题</slot>
          <!--通过slot获取传入内容-->
          <slot></slot>
          <span class="message-box-close" 
            @click="toggle">X</span>
        </div>
      `,
      mounted() {
        this.$bus.$on('message-close', () => {
          this.toggle()
        })
      },
      methods: {
        toggle() {
          this.show = !this.show;
        }
      },
    })

    // 实现自定义指令
    Vue.directive('focus', {
      inserted(el, binding) {
        el.focus()
      }
    })

    // v-permission="'admin'"
    Vue.directive('permission', {
      inserted(el, binding) {
        console.log(binding);
        // 若指定用户角色和当前用户角色不匹配则删除当前指令绑定的元素
        if (role !== binding.value) {
          el.parentElement.removeChild(el)
        }
      }
    })

    // 课程新增组件
    Vue.component('course-add', {
      props: ['val'],
      model: {
        value: 'val',
        event: 'change'
      },
      template: `
        <div>
          <!-- 用户输入 -->
          <p>
            <input type="text" :value="val" 
              @change="onChange"
              v-on:keydown.enter="addCourse"
              ref="inp" v-focus>
            <button @click="addCourse">新增</button>
          </p>
        </div>
      `,
      methods: {
        addCourse() {
          // 派发事件通知父组件新增课程
          this.$emit('add-course')

        },
        onChange(e) {
          this.$emit('change', e.target.value)
        }
      },
      // mounted () {
      //   this.$refs.inp.focus();
      // },
    })

    // 过滤器
    // Vue.filter('currency', function(value){
    //   return value;
    // })

    // 课程列表组件
    Vue.component('course-list', {
      data() {
        return {
          selectedCourse: '',
        }
      },
      props: {
        courses: {
          type: Array,
          default: []
        }
      },
      template: `
        <div>
            <!-- 条件渲染 -->
            <p v-if="courses.length == 0">没有任何课程信息</p>
            
            <!-- 列表渲染 -->
            <!-- <div v-for="c in courses" :key="c" 
              :class="{active: selectedCourse === c}" @click="selectedCourse = c">
              {{ c }}
            </div> -->
            <!-- style -->
            <div class="course-list" v-else>
              <div v-for="c in courses" :key="c.name"
                :style="{backgroundColor: (selectedCourse === c ? '#ddd' : 'transparent')}"
                @click="selectedCourse = c">
                {{ c.name }} - {{ c.price | currency('￥') }}
              </div>
            </div>
        </div>
      `,
      filters: {
        currency(value, symbol = '￥') {
          return symbol + value
        }
      }
    })

    // 模拟异步数据调用
    function getCourses() {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve([{ name: 'web全栈' }, { name: 'web高级' }])
        }, 2000);
      })
    }

    // 1.创建vue实例
    const app = new Vue({
      el: '#app',
      data() {
        return {
          title: '开课吧购物车',
          course: '',
          courses: [],
          totalCount: 0,
          // show: false,
          // showWarn: false,
          price: 0,
        }
      },
      async created() {
        // 组件实例已创建，由于未挂载，dom不存在
        const courses = await getCourses()
        this.courses = courses

        // 批量更新商品价格
        this.batchUpdate()
      },
      // mounted(){},
      methods: {
        addCourse() {
          if (this.course) {
            // 添加course到数组
            this.courses.push({ name: this.course })
            this.course = ''

            // 显示提示信息
            // this.show = true
            this.$refs.msgSuccess.toggle()
          } else {
            // 显示错误信息
            // this.showWarn = true
            this.$refs.msgWarning.toggle()
          }

        },
        batchUpdate() {
          this.courses.forEach(c => {
            // c.price = this.price
            this.$set(c, 'price', this.price)
            // Vue.set(c, 'price', this.price)
          })
        }
      },
      computed: {
        total() {
          // 计算属性有缓存性：如果值没有发生变化，则页面不回重新渲染
          return this.courses.length + '门'
        }
      },
      // 默认情况下watch初始化时不执行
      // watch: {
      //   courses(newValue, oldValue) {
      //     this.totalCount = newValue.length + '门'
      //   }
      // },
      watch: {
        courses: {
          immediate: true, // 立即执行一次
          // deep: true,
          handler(newValue, oldValue) {
            this.totalCount = newValue.length + '门'
          }
        }
      },
    })

  </script>
</body>

</html>